import 'dart:math';

import 'package:flutter/material.dart';
import 'bezier_util.dart';

class GestureBezierDemo extends StatefulWidget {
  GestureBezierDemo({Key? key}) : super(key: key);

  @override
  State<GestureBezierDemo> createState() => _GestureBezierDemoState();
}

class _GestureBezierDemoState extends State<GestureBezierDemo> {
  var points = <Offset>[];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Listener(
        onPointerUp: ((event) {
          print('1: ${event.localPosition}');
          points.add(event.localPosition);
          setState(() {});
        }),
        onPointerSignal: ((event) {
          print(event.toString());
        }),
        onPointerCancel: ((event) {
          print('2:${event.localPosition}');
        }),
        behavior: HitTestBehavior.opaque,
        child: CustomPaint(
          foregroundPainter: GestureBezierPainter(points: points),
          child: Container(
            width: MediaQuery.of(context).size.width,
            height: MediaQuery.of(context).size.height,
            color: Color(0xFFF5F5F5),
          ),
        ),
      ),
      floatingActionButton: IconButton(
        onPressed: () {
          if (points.isNotEmpty) {
            points.removeLast();
            setState(() {});
          }
        },
        icon: Icon(
          Icons.backspace,
          color: Colors.blue,
        ),
      ),
    );
  }
}

class GestureBezierPainter extends CustomPainter {
  GestureBezierPainter({required this.points});
  final List<Offset> points;
  @override
  void paint(Canvas canvas, Size size) {
    print(size);
    canvas.drawColor(Color(0xFFF1F1F1), BlendMode.color);
    var paint = Paint()..color = Color(0xFFE53020);
    paint.strokeWidth = 2.0;
    paint.style = PaintingStyle.stroke;
    for (var point in points) {
      canvas.drawCircle(point, 2.0, paint);
    }
    // 拆分
    paint.color = Color(0xFF2480F0);
    drawCurves(canvas, paint, points);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }

  void drawCurves(Canvas canvas, Paint paint, List<Offset> points) {
    if (points.length <= 1) {
      return;
    }
    if (points.length == 2) {
      canvas.drawLine(points[0], points[1], paint);
      return;
    }
    if (points.length == 3) {
      _draw2OrderBezierCurves(canvas, paint, points);
      return;
    }
    if (points.length == 4) {
      _draw3OrderBezierCurves(canvas, paint, points);
      return;
    }
    var subPoints = points.sublist(0, 4);
    drawCurves(canvas, paint, subPoints);
    drawCurves(canvas, paint, points.sublist(3));
  }

  _draw3OrderBezierCurves(Canvas canvas, Paint paint, List<Offset> points) {
    assert(points.length == 4);
    var yGap = 60.0;
    var path = Path();
    path.moveTo(points[0].dx, points[0].dy);
    for (var t = 1; t <= 100; t += 1) {
      var curvePoint = BezierUtil.get3OrderBezierPoint(
          points[0], points[1], points[2], points[3], t / 100.0);

      path.lineTo(curvePoint.dx, curvePoint.dy);
    }
    canvas.drawPath(path, paint);
  }

  _draw2OrderBezierCurves(Canvas canvas, Paint paint, List<Offset> points) {
    assert(points.length == 3);
    var path = Path();
    path.moveTo(points[0].dx, points[0].dy);
    for (var t = 1; t <= 100; t += 1) {
      var curvePoint = BezierUtil.get2OrderBezierPoint(
          points[0], points[1], points[2], t / 100.0);

      path.lineTo(curvePoint.dx, curvePoint.dy);
    }
    canvas.drawPath(path, paint);
  }
}
